import Constant from './ui-constant';

export default function UIBox (Base=class {}){
    return class UIBox extends Base{
        constructor(options={}){
            super(options);
            this.isBoxComponent=true;
            this.childrenPos={};
        }

        get uiType(){
            return Constant.TYPE_COMPONENT_BOX;
        }

        alignChildrenOnY() {
            const ALIGNMENT = this.getAlignContent();
            const Y_TARGET = (this.getHeight() / 2) - (this.padding || 0);
            if ( ALIGNMENT !== Constant.VALUE_CENTER && ALIGNMENT !== Constant.VALUE_TOP && ALIGNMENT !== Constant.VALUE_BOTTOM ) {
                console.warn(`alignContent === '${ ALIGNMENT }' is not supported on this direction.`);
            }
            this.children.forEach( (child)=> {
                if ( !child.isBoxComponent ) return;
                let offset;
                if ( ALIGNMENT === Constant.VALUE_TOP ) {
                    offset = Y_TARGET - (child.getHeight() / 2) - (child.margin || 0) ;
                } else if ( ALIGNMENT === Constant.VALUE_BOTTOM ) {
                    offset = -Y_TARGET + (child.getHeight() / 2) + (child.margin || 0) ;
                }
                this.childrenPos[ child.id ].y = offset || 0;
            });
        }
        alignChildrenOnX() {
            const ALIGNMENT = this.getAlignContent();
            const X_TARGET = ( this.getWidth() / 2 ) - ( this.padding || 0 );
            if ( ALIGNMENT !== Constant.VALUE_CENTER && ALIGNMENT !== Constant.VALUE_RIGHT && ALIGNMENT !== Constant.VALUE_LEFT ) {
                console.warn(`alignContent === '${ ALIGNMENT }' is not supported on this direction.`)
            }
            this.children.forEach( (child)=> {
                if ( !child.isBoxComponent ) return;
                let offset;
                if ( ALIGNMENT === Constant.VALUE_RIGHT ) {
                    offset = X_TARGET - ( child.getWidth() / 2 ) - ( child.margin || 0 ) ;
                } else if ( ALIGNMENT === Constant.VALUE_LEFT ) {
                    offset = - X_TARGET + ( child.getWidth() / 2 ) + ( child.margin || 0 ) ;
                }
                this.childrenPos[ child.id ].x = offset || 0;
            });
        }
        setChildrenXPos( startPos ) {
            const JUSTIFICATION = this.getJustifyContent();
            if ( JUSTIFICATION !==Constant.VALUE_CENTER && JUSTIFICATION !== Constant.VALUE_START && JUSTIFICATION !== Constant.VALUE_END) {
                console.warn(`justifiyContent === '${ JUSTIFICATION }' is not supported`);
            }
            this.children.reduce( (accu, child)=> {
                if ( !child.isBoxComponent ) return accu;
                const CHILD_ID = child.id;
                const CHILD_WIDTH = child.getWidth();
                const CHILD_MARGIN = child.margin || 0;
                accu += CHILD_MARGIN * -Math.sign( startPos );
                this.childrenPos[ CHILD_ID ] = {
                    x: accu + ((CHILD_WIDTH / 2) * -Math.sign( startPos )),
                    y: 0
                };
                return accu + (-Math.sign( startPos ) * (CHILD_WIDTH + CHILD_MARGIN));
            }, startPos );
            if ( JUSTIFICATION === Constant.VALUE_END || JUSTIFICATION === Constant.VALUE_CENTER ) {
                let offset = (startPos * 2) - (this.getChildrenSideSum( Constant.STYLE_WIDTH) * Math.sign(startPos));
                if ( JUSTIFICATION === Constant.VALUE_CENTER ) offset /= 2;
                this.children.forEach( (child)=> {
                    if ( !child.isBoxComponent ) return;
                    this.childrenPos[ child.id ].x -= offset;
                });
            }
        }
        setChildrenYPos( startPos ) {
            const JUSTIFICATION = this.getJustifyContent();
            this.children.reduce( (accu, child)=> {
                if ( !child.isBoxComponent ) return accu;
                const CHILD_ID = child.id;
                const CHILD_HEIGHT = child.getHeight();
                const CHILD_MARGIN = child.margin || 0;
                accu += CHILD_MARGIN * -Math.sign( startPos );
                this.childrenPos[ CHILD_ID ] = {
                    x: 0,
                    y: accu + ((CHILD_HEIGHT / 2) * -Math.sign( startPos ))
                };
                return accu + (-Math.sign( startPos ) * (CHILD_HEIGHT + CHILD_MARGIN));
            }, startPos );
            if ( JUSTIFICATION === Constant.VALUE_END || JUSTIFICATION === Constant.VALUE_CENTER ) {
                let offset = (startPos * 2) - (this.getChildrenSideSum( Constant.STYLE_HEIGHT) * Math.sign(startPos));
                if ( JUSTIFICATION === Constant.VALUE_CENTER ) offset /= 2;
                this.children.forEach( (child)=> {
                    if ( !child.isBoxComponent ) return;
                    this.childrenPos[ child.id ].y -= offset;
                });
            }
        }
        computeChildrenPosition() {
            if ( this.children.length > 0 ) {
                const DIRECTION = this.getContentDirection();
                let X_START, Y_START;
                switch ( DIRECTION ) {
                    case Constant.VALUE_ROW:
                        X_START = this.getInnerWidth() / 2;
                        this.setChildrenXPos( -X_START );
                        this.alignChildrenOnY();
                        break;
                    case Constant.VALUE_ROW_REVERSE:
                        X_START = this.getInnerWidth() / 2;
                        this.setChildrenXPos( X_START );
                        this.alignChildrenOnY();
                        break;
                    case Constant.VALUE_COLUMN:
                        Y_START = this.getInnerHeight() / 2;
                        this.setChildrenYPos( Y_START );
                        this.alignChildrenOnX();
                        break;
                    case Constant.VALUE_COLUMN_REVERSE:
                        Y_START = this.getInnerHeight() / 2;
                        this.setChildrenYPos( -Y_START );
                        this.alignChildrenOnX();
                        break;
                }
            }
        }
        setPosFromParentRecords() {
            if ( this.getUIParent() && this.getUIParent().childrenPos[ this.id ] ) {
                this.position.x = ( this.getUIParent().childrenPos[ this.id ].x );
                this.position.y = ( this.getUIParent().childrenPos[ this.id ].y );
            }
        }
        getWidth() {
            return this.width || this.getInnerWidth() + ( this.padding * 2 || 0 );
        }
        getHeight() {
            return this.height || this.getInnerHeight() + ( this.padding * 2 || 0 );
        }
        getInnerWidth() {
            const DIRECTION = this.getContentDirection();
            switch ( DIRECTION ) {
                case Constant.VALUE_ROW:
                case Constant.VALUE_ROW_REVERSE:
                    return this.width - (this.padding * 2 || 0) || this.getChildrenSideSum(Constant.STYLE_WIDTH);
                case Constant.VALUE_COLUMN :
                case Constant.VALUE_COLUMN_REVERSE:
                    return this.getHighestChildSizeOn(Constant.STYLE_WIDTH );
                default :
                    console.error(`Invalid contentDirection : ${ DIRECTION }`);
                    break;
            }
        }
        getInnerHeight() {
            const DIRECTION = this.getContentDirection();
            switch ( DIRECTION ) {
                case Constant.VALUE_ROW:
                case Constant.VALUE_ROW_REVERSE:
                    return this.getHighestChildSizeOn(Constant.STYLE_HEIGHT);
                case Constant.VALUE_COLUMN:
                case Constant.VALUE_COLUMN_REVERSE:
                    return this.height - (this.padding * 2 || 0) || this.getChildrenSideSum(Constant.STYLE_HEIGHT);
                default :
                    console.error(`Invalid contentDirection : ${ DIRECTION }`);
                    break;
            }
        }
        getChildrenSideSum( dimension ) {
            return this.children.reduce((accu, child)=> {
                if ( !child.uiType!==Constant.TYPE_COMPONENT_BOX ) return accu;
                const margin = (child.margin * 2) || 0;
                const CHILD_SIZE = (dimension === Constant.STYLE_WIDTH) ?
                    ( child.getWidth() + margin ) :
                    ( child.getHeight() + margin );
                return accu + CHILD_SIZE;
            }, 0 );
        }
        getHighestChildSizeOn( direction ) {
            return this.children.reduce((accu, child)=> {
                if ( !child.uiType!==Constant.TYPE_COMPONENT_BOX ) return accu;
                const margin = child.margin || 0;
                const maxSize = direction === Constant.STYLE_WIDTH ?
                    child.getWidth() + (margin * 2) :
                    child.getHeight() + (margin * 2) ;
                return Math.max(accu, maxSize);
            }, 0 );
        }

    }
}